Skip to content

use rtos semaphore as mutex in esp-radio refcount - #6329

Open
tommasoclini wants to merge 8 commits into
esp-rs:mainfrom
tommasoclini:rtos_refcount
Open

tommasoclini wants to merge 8 commits into
esp-rs:mainfrom
tommasoclini:rtos_refcount

Conversation

@tommasoclini

@tommasoclini tommasoclini commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Submission Checklist 📝

  • I have used cargo xtask fmt command to ensure that all changed code is formatted correctly.
  • I have added changelog entries and/or migration guide notes in the sections below, or I will ask a maintainer to add the skip-changelog or manual-changelog label as appropriate.
  • My changes are in accordance to the esp-rs developer guidelines

Extra:

Pull Request Details 📖

Description

Use an esp-radio-rtos-driver mutex in esp_radio::refcount::Refcount to avoid spinning when synchronizing deinitialization and initialization.

Testing

todo


Changelog

esp-radio

  • Changed: refcount::Refcount now uses esp_radio_rtos_driver's api to avoid spinning, now on wrong decrement calls or counter overflow a panic takes place.

@tommasoclini tommasoclini changed the title use rtos semaphore as mutex use rtos semaphore as mutex in esp-radio refcount Sep 16, 2026
@tommasoclini
tommasoclini marked this pull request as ready for review September 17, 2026 16:41
Comment thread esp-radio/src/refcount.rs
Comment on lines +32 to +67
fn use_sem_or_init<T>(&self, f: impl FnOnce(&SemaphoreHandle) -> T) -> T {
if self.sem.load(Ordering::Relaxed).is_null() {
core::hint::cold_path();

let sem = SemaphoreHandle::new(SemaphoreKind::Mutex).leak();

if self
.sem
.compare_exchange(
null_mut(),
sem.as_ptr(),
Ordering::Release,
Ordering::Relaxed,
)
.is_err()
{
core::hint::cold_path();

drop(unsafe { SemaphoreHandle::from_ptr(sem) });
}
}

let sem = unsafe { SemaphorePtr::new_unchecked(self.sem.load(Ordering::Acquire)) };
f(unsafe { SemaphoreHandle::ref_from_ptr(&sem) })
}

fn try_use_sem<T>(&self, f: impl FnOnce(&SemaphoreHandle) -> T) -> Option<T> {
if self.sem.load(Ordering::Relaxed).is_null() {
core::hint::cold_path();

None
} else {
let sem = unsafe { SemaphorePtr::new_unchecked(self.sem.load(Ordering::Acquire)) };
Some(f(unsafe { SemaphoreHandle::ref_from_ptr(&sem) }))
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see much point in splitting these apart. Both are single-use wrappers, and they do roughly the same thing. If you merge them with the call sites, at least one layer of the callback lasagna would go away.

Comment thread esp-radio/src/refcount.rs
})
}

fn try_lock<T>(&self, f: impl FnOnce(&mut u32) -> T) -> Option<T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd just get rid of try_lock entirely, I don't see the value in it. Yes, it's wasteful to initialize a mutex if we are going to panic anyway, but now I have to figure out why this even exists and what the intended use case is. From what I can see, lock can be used in all the 1 callsites.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants